<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>JavaScript Calculator</title>
    <style>
        @import "https://fonts.googleapis.com/css?family=Share+Tech+Mono";
        @font-face {
            font-family: "Digital";
            src: url("//db.onlinewebfonts.com/t/8e22783d707ad140bffe18b2a3812529.eot");
            src: url("//db.onlinewebfonts.com/t/8e22783d707ad140bffe18b2a3812529.eot?#iefix") format("embedded-opentype"), url("//db.onlinewebfonts.com/t/8e22783d707ad140bffe18b2a3812529.woff2") format("woff2"), url("//db.onlinewebfonts.com/t/8e22783d707ad140bffe18b2a3812529.woff") format("woff"), url("//db.onlinewebfonts.com/t/8e22783d707ad140bffe18b2a3812529.ttf") format("truetype"), url("//db.onlinewebfonts.com/t/8e22783d707ad140bffe18b2a3812529.svg#Digital-7") format("svg");
        }
        #app {
            height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        body {
            background: #c2c2d6;
            -webkit-touch-callout: none;
            -moz-user-select: none;
            -ms-user-select: none;
            -webkit-user-select: none;
            user-select: none;
            cursor: default;
        }

        .calculator {
            border: 2px solid #47476b;
            padding: 5px;
            background: black;
            width: 320px;
            position: relative;
        }

        .formulaScreen {
            min-height: 20px;
            font-family: digital;
            font-size: 20px;
            color: orange;
            text-align: right;
            vertical-align: text-top;
            line-height: 20px;
            overflow-wrap: break-word;
            word-wrap: break-word;
        }

        .outputScreen {
            font-size: 29px;
            font-family: digital;
            color: white;
            text-align: right;
            line-height: 35px;
        }

        button {
            position: relative;
            height: 65px;
            width: 80px;
            color: white;
            outline: 1px solid black;
            border: none;
            background: #4d4d4d;
            font-family: Share Tech Mono, monospace;
            font-size: 20px;
            cursor: default;
        }
        button:hover {
            color: black;
            outline: .05em solid grey;
            z-index: 3;
        }

        .jumbo {
            width: 160px;
        }

        .author {
            text-align: center;
            font-family: Share Tech Mono, sans;
            margin-top: 15px;
        }
        .author a {
            text-decoration: none;
            color: #00264d;
            line-height: 26px;
        }

    </style>
</head>
<body>
<div id='app'></div>
</body>
</html>
<script>
    // To see a more advanced version of this app with features such as toggle sign and Clear Entry buttons, see this pen https://codepen.io/no_stack_dub_sack/full/jrxpKP/

    // coded by @no-stack-dub-sack (github) / @no_stack_sub_sack (codepen)

    // PROJECTOR SELECTOR FOR EXTERNAL TEST SCRIPT:
    const projectName = 'javascript-calculator';
    localStorage.setItem('example_project', 'Javascript Calculator');

    // VARS:
    const isOperator = /[x/+‑]/,
        endsWithOperator = /[x+‑/]$/,
        clearStyle = {background: '#ac3939'},
        operatorStyle = {background: '#666666'},
        equalsStyle = {
            background: '#004466',
            position: 'absolute',
            height: 130,
            bottom: 5
        };

    // COMPONENTS:
    class Calculator extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                currentVal: '0',
                prevVal: '0',
                formula: '',
                currentSign: 'pos',
                lastClicked: ''
            }
            this.maxDigitWarning = this.maxDigitWarning.bind(this);
            this.handleOperators = this.handleOperators.bind(this);
            this.handleEvaluate = this.handleEvaluate.bind(this);
            this.initialize = this.initialize.bind(this);
            this.handleDecimal = this.handleDecimal.bind(this);
            this.handleNumbers = this.handleNumbers.bind(this);
        }

        maxDigitWarning() {
            this.setState({
                currentVal: 'Digit Limit Met',
                prevVal: this.state.currentVal
            });
            setTimeout(() => this.setState({currentVal: this.state.prevVal}), 1000);
        }

        handleEvaluate() {
            if (!this.state.currentVal.includes('Limit')) {
                let expression = this.state.formula;
                if (endsWithOperator.test(expression)) expression = expression.slice(0, -1);
                expression = expression.replace(/x/g, "*").replace(/‑/g, "-");
                let answer = Math.round(1000000000000 * eval(expression)) / 1000000000000;
                this.setState({
                    currentVal: answer.toString(),
                    formula: expression.replace(/\*/g, '⋅').replace(/-/g, '‑') + '=' + answer,
                    prevVal: answer,
                    evaluated: true
                });
            }
        }

        handleOperators(e) {
            if (!this.state.currentVal.includes('Limit')) {
                this.setState({currentVal: e.target.value,evaluated: false});
                if (this.state.formula.includes('=')) {
                    this.setState({formula: this.state.prevVal + e.target.value}); // comment 1
                } else {
                    this.setState({ // comment 2
                        prevVal: !isOperator.test(this.state.currentVal) ?
                            this.state.formula :
                            this.state.prevVal,
                        formula: !isOperator.test(this.state.currentVal) ?
                            this.state.formula += e.target.value :
                            this.state.prevVal += e.target.value
                    });
                }
            }
        }

        handleNumbers(e) {
            if (!this.state.currentVal.includes('Limit')) {
                this.setState({evaluated: false})
                if (this.state.currentVal.length > 21) {
                    this.maxDigitWarning();
                } else if (this.state.evaluated === true) {
                    this.setState({
                        currentVal: e.target.value,
                        formula: e.target.value != '0' ? e.target.value : '',
                    });
                } else {
                    this.setState({
                        currentVal:
                            this.state.currentVal == '0' ||
                            isOperator.test(this.state.currentVal) ?
                                e.target.value : this.state.currentVal + e.target.value,
                        formula:
                            this.state.currentVal == '0' && e.target.value == '0' ?
                                this.state.formula :
                                /([^.0-9]0)$/.test(this.state.formula) ?
                                    this.state.formula.slice(0, -1) + e.target.value :
                                    this.state.formula + e.target.value,
                    });
                }
            }
        }

        handleDecimal() {
            if (this.state.evaluated === true) {
                this.setState({
                    currentVal: '0.',
                    formula: '0.',
                    evaluated: false});
            } else if (!this.state.currentVal.includes('.') &&
                !this.state.currentVal.includes('Limit')) {
                this.setState({evaluated: false})
                if (this.state.currentVal.length > 21) {
                    this.maxDigitWarning();
                } else if (endsWithOperator.test(this.state.formula) ||
                    this.state.currentVal == '0' && this.state.formula === '') {
                    this.setState({
                        currentVal: '0.',
                        formula: this.state.formula + '0.'
                    });
                } else {
                    this.setState({
                        currentVal: this.state.formula.match(/(-?\d+\.?\d*)$/)[0] + '.',
                        formula: this.state.formula + '.',
                    });
                }
            }
        }

        initialize() {
            this.setState({
                currentVal: '0',
                prevVal: '0',
                formula: '',
                currentSign: 'pos',
                lastClicked: ''
            });
        }

        render() {
            return (
                <div>
                    <div className='calculator'>
                        <Formula formula={this.state.formula.replace(/x/g, '⋅')} />
                        <Output currentValue={this.state.currentVal} />
                        <Buttons evaluate={this.handleEvaluate}
                                 operators={this.handleOperators}
                                 initialize={this.initialize}
                                 decimal={this.handleDecimal}
                                 numbers={this.handleNumbers} />
                    </div>
                    <div className="author"> Designed and Coded By <br />
                        <a target="_blank" href="https://goo.gl/6NNLMG">
                            Peter Weinberg
                        </a>
                    </div>
                </div>
            )
        }
    };

    class Buttons extends React.Component {
        render() {
            return (
                <div>
                    <button id="clear"    value='AC' onClick={this.props.initialize} className='jumbo' style={clearStyle}>AC</button>
                    <button id="divide"   value='/'  onClick={this.props.operators} style={operatorStyle}>/</button>
                    <button id="multiply" value='x'  onClick={this.props.operators} style={operatorStyle}>x</button>
                    <button id="seven"    value='7'  onClick={this.props.numbers} >7</button>
                    <button id="eight"    value='8'  onClick={this.props.numbers} >8</button>
                    <button id="nine"     value='9'  onClick={this.props.numbers} >9</button>
                    <button id="subtract" value='‑'  onClick={this.props.operators} style={operatorStyle}>-</button>
                    <button id="four"     value='4'  onClick={this.props.numbers} >4</button>
                    <button id="five"     value='5'  onClick={this.props.numbers} >5</button>
                    <button id="six"      value='6'  onClick={this.props.numbers} >6</button>
                    <button id="add"      value='+'  onClick={this.props.operators} style={operatorStyle}>+</button>
                    <button id="one"      value='1'  onClick={this.props.numbers} >1</button>
                    <button id="two"      value='2'  onClick={this.props.numbers} >2</button>
                    <button id="three"    value='3'  onClick={this.props.numbers} >3</button>
                    <button id="zero"     value='0'  onClick={this.props.numbers} className='jumbo'>0</button>
                    <button id="decimal"  value='.'  onClick={this.props.decimal} >.</button>
                    <button id="equals"   value='='  onClick={this.props.evaluate} style={equalsStyle}>=</button>
                </div>
            );
        }
    }

    class Output extends React.Component {
        render () {
            return <div id="display" className="outputScreen">{this.props.currentValue}</div>
        }
    };

    class Formula extends React.Component {
        render() {
            return <div className="formulaScreen">{this.props.formula}</div>
        }
    };

    ReactDOM.render(<Calculator />, document.getElementById('app'));


</script>